package com.titan.core.utils.data;

import java.math.BigDecimal;
import java.math.BigInteger;


/**
 * @author 周成功
 * @email 86898837@qq.com
 * @date 2020年02月10日
 */
public class ArithUtils{

    //默认除法运算精度
    private static final int DEF_DIV_SCALE = 10;

    //这个类不能实例化
    private ArithUtils(){}

    /**
     * 提供精确的加法运算。
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).doubleValue();
    }
    public static String addToString(String...values){
        BigDecimal sum = new BigDecimal("0");
        for (int i = 0; i < values.length; i++) {
            sum = sum.add(new BigDecimal(values[i]));
        }
        return sum.toPlainString();
    }
//    public static double add(double v1, double v2) {
//        return add(FormatUtils.toString(v1), FormatUtils.toString(v2));
//    }
    public static double add(double...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        // 求和
        String sum = "0";
        for (int i = 0; i < values.length; i++) {
            sum = addToString(sum, FormatUtils.toString(values[i]));
        }
        return FormatUtils.toDouble(sum);
    }    

    
    /**
     * 提供精确的减法运算。
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).doubleValue();
    }
    public static String subToString(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).toPlainString();
    }
    public static double sub(double v1,double v2){
        return sub(FormatUtils.toString(v1), FormatUtils.toString(v2));
    }

    
    /**
     * 提供精确的乘法运算。
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).doubleValue();
    }
    public static String mulToString(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).toPlainString();
    }
    public static double mul(double v1, double v2){
        return mul(FormatUtils.toString(v1), FormatUtils.toString(v2));
    }

    
    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到
     * 小数点以后10位，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(String v1, String v2){
        return div(v1, v2, DEF_DIV_SCALE);
    }
    public static String divToString(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, BigDecimal.ROUND_DOWN).toPlainString();
    }
    public static double div(double v1, double v2){
        return div(Double.toString(v1), Double.toString(v2));
    }

    public static int divToUp(int v1, int v2){
        return divToUp(Integer.toString(v1), Integer.toString(v2));
    }
    public static int divToUp(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, BigDecimal.ROUND_UP).intValue();
    }
    public static int divToDown(String v1, String v2){
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2, BigDecimal.ROUND_DOWN).intValue();
    }
    
    
    
    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指
     * 定精度，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(String v1, String v2, int scale, int roundingMode){
        if(scale<0){
            throw new IllegalArgumentException("精确除法运算错误，指定的精确数必须大于或等于0");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.divide(b2,scale,roundingMode).doubleValue();
    }
    public static double div(String v1, String v2, int scale){
        return div(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
    }
    public static String divToString(String v1, String v2, int scale){
        return FormatUtils.toString(div(v1, v2, scale));
    }
    public static double div(double v1,double v2,int scale){
        return div(FormatUtils.toString(v1), FormatUtils.toString(v2), scale);
    }
    
    
    /**
     * 提供精确的小数位四舍五入处理。
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(String v1,int scale){
        if(scale<0){
            throw new IllegalArgumentException("精确四舍五入运算错误，指定的精确数必须大于或等于0");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal("1");
        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    public static String roundToString(double v1, int scale){
        return FormatUtils.toString(round(v1, scale));
    }
    public static String roundToString(String v1, int scale){
        return FormatUtils.toString(round(v1, scale));
    }
    public static double round(double v1, int scale){
        return round(FormatUtils.toString(v1), scale);
    }
    public static int round(double v1){
        BigDecimal b1 = new BigDecimal(FormatUtils.toString(v1));
        BigDecimal b2 = new BigDecimal("1");
        return b1.divide(b2, 0, BigDecimal.ROUND_HALF_UP).intValue();
    }
    
    /**
     * 获得两个数值中大的数值
     * @param v1 String
     * @param v2 String
     * @return double
     */
    public static double max(String...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return FormatUtils.toDouble(values[0]);
        }
        BigDecimal value = new BigDecimal(values[0]);
        for (int i = 1; i < values.length; i++) {
            BigDecimal current = new BigDecimal(values[i]);
            value = value.max(current);
        }
        return value.doubleValue();
    }
    public static double max(double...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        BigDecimal value = new BigDecimal(FormatUtils.toString(values[0]));
        for (int i = 1; i < values.length; i++) {
            BigDecimal current = new BigDecimal(FormatUtils.toString(values[i]));
            value = value.max(current);
        }
        return value.doubleValue();
    }
    public static int max(int...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        int value = values[0];
        for (int i = 1; i < values.length; i++) {
            if(value < values[i]) {
                value = values[i];
            }
        }
        return value;
    }    
    public static long max(long...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        long value = values[0];
        for (int i = 1; i < values.length; i++) {
            if(value < values[i]) {
                value = values[i];
            }
        }
        return value;
    }    

    
    /**
     * 获得两个数值中小的数值
     * @param v1 String
     * @param v2 String
     * @return double
     */
    public static double min(String...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return FormatUtils.toDouble(values[0]);
        }
        BigDecimal value = new BigDecimal(values[0]);
        for (int i = 1; i < values.length; i++) {
            BigDecimal current = new BigDecimal(values[i]);
            value = value.min(current);
        }
        return value.doubleValue();
    }
    public static double min(double...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        BigDecimal value = new BigDecimal(FormatUtils.toString(values[0]));
        for (int i = 1; i < values.length; i++) {
            BigDecimal current = new BigDecimal(FormatUtils.toString(values[i]));
            value = value.min(current);
        }
        return value.doubleValue();
    }
    public static int min(int...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        int value = values[0];
        for (int i = 1; i < values.length; i++) {
            if(value > values[i]) {
                value = values[i];
            }
        }
        return value;
    }    
    public static long min(long...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        long value = values[0];
        for (int i = 1; i < values.length; i++) {
            if(value > values[i]) {
                value = values[i];
            }
        }
        return value;
    }    
    
    // 计算平均数
    public static double average(double...values) {
        AssertUtils.assertTrue((values!=null && values.length>0), "参数不能为空");
        if(values.length==1) {
            return values[0];
        }
        // 求和
        double sum = add(values);
        return div(sum, values.length);
    }
    
    // 计算base的exponent次方
    public static long pow(long base, int exponent) {
        return BigInteger.valueOf(base).pow(exponent).longValue();
    }
    
}
